import { logger } from '../types/constants'
import { SYMBOLS } from '../types/interfaces'

/**
 * Web 请求处理类
 * const webRequestHandler = WebRequestHandler.getInstance()
 * 1）添加广告拦截规则
 * webRequestHandler.addRuleGroup('ad-blocking', [
 *   { selector: '*://www.google-analytics.com/*', action: 'cancel' },
 * ])
 */
export class WebRequestHandler {
  private readonly name: string = 'WebRequestHandler'
  static instance: WebRequestHandler
  private ruleGroups: Map<string, any[]> = new Map()

  static getInstance(): WebRequestHandler {
    if (!WebRequestHandler.instance) {
      WebRequestHandler.instance = new WebRequestHandler()
    }

    return WebRequestHandler.instance
  }

  /**
   * 添加规则组
   */
  addRuleGroup(groupName: string, rules: any[]): void {
    this.ruleGroups.set(groupName, rules)
    this.applyAllRules()
  }

  /**
   * 移除规则组
   */
  removeRuleGroup(groupName: string): void {
    this.ruleGroups.delete(groupName)
    this.applyAllRules()
  }

  /**
   * 应用所有规则
   */
  private applyAllRules(): void {
    const allRules: any[] = []

    // 合并所有规则组
    this.ruleGroups.forEach((rules) => {
      allRules.push(...rules)
    })

    const ruleCount = allRules.length

    if (ruleCount > 0) {
      GM_webRequest(allRules, this.handleAllInterceptions.bind(this))
      logger.info(`[${this.name}] 已应用 ${ruleCount} 条规则`)
    }
    else {
      GM_webRequest([], () => {})
      logger.info(`[${this.name}] 规则已全部清空`)
    }
  }

  /**
   * 处理所有拦截回调
   */
  private handleAllInterceptions(info: string, message: string, details: any): void {
    const ruleSource = this.findRuleSource(details.rule)

    logger.info(`[${this.name}] ${SYMBOLS.UI.BULLSEYE} '${ruleSource}' 规则触发`, {
      type: info,
      message,
      url: details.url,
      redirect: details.redirect_url,
    })
  }

  /**
   * 查找规则来源
   */
  private findRuleSource(rule: any): string {
    if (!rule)
      return 'unknown'

    for (const [groupName, rules] of this.ruleGroups) {
      if (rules.includes(rule)) {
        return groupName
      }
    }

    return 'unknown'
  }
}
